/**
 * vue2源码目录
 * src\compiler\parser\html-parser.ts
 */
const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`
const qnameCapture = `((?:${ncname}\\:)?${ncname})`
// 匹配开始标签
const startTagOpen = new RegExp(`^<${qnameCapture}`)
// 匹配结束标签
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`)
// 匹配属性
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/
// 匹配开始标签结束
const startTagClose = /^\s*(\/?)>/

/**
 * 解析HTML
 * (单标签匹配的问题这里没有解决，如hr,br,img)
 */
export function parseHTML(html) {
  const ELEMENT_TYPE = 1 // 取自html的nodeType
  const TEXT_TYPE = 3 // 取自html的nodeType
  const stack = [] // 栈形结构，用来生成树
  let currentParent // 指向stack中的最后一个
  let root // 记录根节点（生成的树）

  function createAstELement(tag, attrs) {
    return {
      tag,
      attrs,
      type: ELEMENT_TYPE,
      parent: null,
      children: []
    }
  }
  function getStart(tegName, attrs) {
    // console.log("🚀 - tegName:", tegName)
    let node = createAstELement(tegName, attrs)
    if (!root) {
      root = node
    }
    if (currentParent) {
      node.parent = currentParent
      currentParent.children.push(node)
    }
    stack.push(node)
    currentParent = node
  }
  function getText(text) {
    text = text.replace(/\s/g, "")
    text &&
      currentParent.children.push({
        text,
        type: TEXT_TYPE,
        parent: currentParent
      })
  }
  function getEnd(tegName) {
    // console.log("============================", tegName);
    stack.pop()
    currentParent = stack[stack.length - 1]
  }

  // 步进
  function advance(length) {
    html = html.substring(length)
  }

  // 解析开始标签
  function parseStartTag() {
    let match
    let start = html.match(startTagOpen)
    if (start) {
      match = {
        tegName: start[1],
        attrs: []
      }
      advance(start[0].length)

      let attr, end // attr 为每次匹配的属性，end 为结束符
      while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {
        match.attrs.push({ name: attr[1], value: attr[3] || attr[4] || attr[5] })
        advance(attr[0].length)
      }
      if (end) {
        advance(end[0].length)
      }
    }
    return match
  }

  while (html) {
    // flag 为 0 表示匹配到了标签，注意标签开始和结束都是以 < 开头
    let flag = html.indexOf("<")
    if (flag == 0) {
      let startMatch = parseStartTag()
      // 开始标签匹配完成，重新走循环
      if (startMatch) {
        // console.log("🚀 - startMatch:", startMatch)
        getStart(startMatch.tegName, startMatch.attrs)
        continue
      }

      // 匹配结束标签
      let endMatch = html.match(endTag)
      if (endMatch) {
        getEnd(endMatch[1])
        advance(endMatch[0].length)
        continue
      }
    }

    // flag 表示匹配到了标签中间的内容
    if (flag > 0) {
      let text = html.substring(0, flag)
      if (text) {
        getText(text)
        advance(text.length)
      }
    }
  }

  return root
}
